特定のセキュリティグループ・ポートが変更されたことをカスタマイズした日本語メールで通知してみた

特定のセキュリティグループ・ポートが変更されたことをカスタマイズした日本語メールで通知してみた

EventBridgeのEventPatternを変更することで、対応可能です。
Clock Icon2024.10.11

こんにちは!AWS事業本部のおつまみです。

みなさん、特定のセキュリティグループ・ポートが変更されたことを検知して、メール通知してほしいなぁと思ったことはありますか?私はあります。
以前こちらのブログにて、特定のセキュリティグループが変更されたことをカスタマイズした日本語メールで通知する方法をご紹介しました。

https://dev.classmethod.jp/articles/notification-by-customized-japanese-email-to-change-specific-sg/#toc-

今回上記のブログで展開したテンプレートにて、以下の追加要望を受けました。

  • 特定ポート(SSH・RDP)の変更のみ通知したい
  • セキュリティグループをパラメータで指定できるようにして欲しい。

この要望に沿って、CloudFormationテンプレートを修正したので、ご紹介します!

メール通知内容は前回と同様な文面となります。

セキュリティグループのRDP_SSH変更通知_-_matsunami_kana_classmethod_jp_-_Classmethod_jp_メール

構成図

今回構築する構成は前回から変更ありません。
前提として、CloudTrailが既に有効化されている環境で構築します。

0fcc3005dd1e02d836fbf471ca4adb2b-1

セキュリティグループを変更してから、ユーザーにメール通知するまでの流れ

①Amazon EventBridge:セキュリティグループの変更イベントを検知。EventBridgeの入力トランスフォーマーで、メールの件名と本文を設定。
②AWS StepFunctions:Amazon SNS publish API を呼び出し、件名と本文を指定して通知。※SNSをEventBridgeのターゲットに直接指定するとメール件名の指定ができません。
③Amazon SNS:指定したアドレス宛にメール通知。

CloudFormationテンプレートを準備

テンプレート内容は以下の通りです。

テンプレート
AWSTemplateFormatVersion: '2010-09-09'
Description: "create Security group change notification"

# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------# 
Parameters:
  PJPrefix:
    Type: String

  SNSTopicName:
    Type: String
    Default: SecurityGroup_Change_Alarm

  Email:
    Type: String
    Default: email_address

  TargetSecurityGroupIds:
    Type: CommaDelimitedList
    Description: If there are multiple target security groups, please enter them separated by [,]
    Default: sg-1234567890abcdef0

Resources:
# ------------------------------------------------------------#
# SNS Topic
# ------------------------------------------------------------# 
  SNSTopic:
    Type: "AWS::SNS::Topic"
    Properties:
      TopicName: !Ref SNSTopicName
      Tags: 
      - 
        Key: "Name"
        Value: !Sub ${PJPrefix}-${SNSTopicName}

# ------------------------------------------------------------#
# SNS Subscription
# ------------------------------------------------------------# 
  Subscription:
    Type: "AWS::SNS::Subscription"
    Properties:
      TopicArn: !Ref SNSTopic
      Endpoint: !Ref Email
      Protocol: "email"

# ------------------------------------------------------------#
# SNS TopicPolicy
# ------------------------------------------------------------# 
  EventTopicPolicy:
    Type: 'AWS::SNS::TopicPolicy'
    Properties:
      PolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service: events.amazonaws.com
            Action: 'sns:Publish'
            Resource: '*'
      Topics:
        - !Ref SNSTopic

# ------------------------------------------------------------#
# StepFunction メール本文カスタマイズ用
# ------------------------------------------------------------# 
  SNSStateMachine:
    Type: "AWS::StepFunctions::StateMachine"
    Properties:
      DefinitionString: !Sub |-
            {
              "StartAt": "PublishSns",
              "States": {
                "PublishSns": {
                  "Type": "Task",
                  "Resource": "arn:aws:states:::sns:publish",
                  "Parameters": {
                    "TopicArn": "arn:aws:sns:${AWS::Region}:${AWS::AccountId}:${SNSTopicName}",
                    "Message.$": "$.message",
                    "Subject.$": "$.subject"
                  },
                  "End": true
                }
              }
            }
      RoleArn: !GetAtt PublishRole.Arn

# ------------------------------------------------------------#
# IAMロール (StepFunction用)
# ------------------------------------------------------------# 
  PublishRole:
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal:
              Service:
                - states.amazonaws.com
            Action: "sts:AssumeRole"
      Path: "/"
      Policies:
        - PolicyName: SNSPublish
          PolicyDocument:
            Statement:
              - Effect: Allow
                Resource:
                  - !Ref SNSTopic
                Action:
                  - sns:Publish

  StateMachineExecuteRole:
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal:
              Service:
                - events.amazonaws.com
            Action: "sts:AssumeRole"
      Path: "/"
      Policies:
        - PolicyName: StateMachineExecute
          PolicyDocument:
            Statement:
              - Effect: Allow
                Resource:
                  - !Ref SNSStateMachine
                Action:
                  - states:StartExecution

# ------------------------------------------------------------#
# EventBridge Rule
# ------------------------------------------------------------# 
  EventBridgeRule:
    Type: AWS::Events::Rule
    DependsOn: SNSTopic
    Properties: 
      Description: !Ref SNSTopicName
      EventBusName: default
      EventPattern: 
        Fn::Sub:
          - |-
            {
              "source": ["aws.ec2"],
              "detail-type": ["AWS API Call via CloudTrail"],
              "detail": {
                "eventSource": ["ec2.amazonaws.com"],
                "eventName": ["AuthorizeSecurityGroupIngress", "AuthorizeSecurityGroupEgress", "RevokeSecurityGroupIngress", "RevokeSecurityGroupEgress"],
                "requestParameters": {
                  "groupId": ${SGIds},
                  "ipPermissions": {
                    "items": {
                      "fromPort": [22, 3389]
                    }
                  }
                }
              }
            }
          - SGIds: !Join
              - ''
              - - '["'
                - !Join
                  - '","'
                  - !Ref TargetSecurityGroupIds
                - '"]'
      Name: !Ref SNSTopicName
      Targets: 
        - Arn: !Ref SNSStateMachine
          Id: step-function
          RoleArn: !GetAtt StateMachineExecuteRole.Arn
          InputTransformer:
            InputPathsMap:
              "Account" : "$.account"
              "SecuritygroupId" : "$.detail.requestParameters.groupId"
              "eventId" : "$.detail.eventID"
              "time" : "$.time"
              "userName" : "$.detail.userIdentity.sessionContext.sessionIssuer.userName"
              "value" : "$.detail"
            InputTemplate: |
              {
                "subject": "セキュリティグループのRDP/SSH変更通知",
                "message": "セキュリティグループ \"<SecuritygroupId>\" が変更されたことを検知しました。 \n詳細は次のとおりです。 \nAccount ID : \"<Account>\" \n発生時間 : \"<time> \"(UTC) \n変更ユーザー名 : \"<userName>\" \nセキュリティグループID : \"<SecuritygroupId>\" \nCloudTrailイベントID : \"<eventId>\" \n\nセキュリティグループの確認方法 \nEC2コンソール画面の左メニュータグより「セキュリティグループ」を選択します。\n検索ウィンドウで「セキュリティグループID」を入力し、セキュリティグループが正しいことを確認してください。 \n\nCloudTrailイベント履歴の確認方法 \nCloudTrailコンソール画面の左メニュータグより「イベント履歴」を選択します。 \n検索ウィンドウで[イベントID]を選択し、「CloudTrailイベントID」入力します。イベント詳細が確認できます。"
              }                                

前回構成からの変更点

前回の構成から以下のような変更を行いました。

  1. TargetSecurityGroupIds パラメータの追加:

    • セキュリティグループをTargetSecurityGroupIds パラメータで指定できるよう変更
    • 単一だけでなく、複数のセキュリティグループIDをカンマ区切りで指定可能
  2. EventBridgeRule EventPatternの変更:

  3. EventBridgeRule InputTemplateの変更:

    • メール通知の件名と本文を特定のセキュリティグループに対する変更であることがわかるよう変更

いざ検証

CloudFromationでデプロイ

パラメータは、以下の値を入れます。

  • Email
    • SNS通知させたいメールアドレス
  • PJPrefix
    • プロジェクト名
  • SNSTopicName
    • SNSのトピック名(デフォルトのままで問題なし)
  • TargetSecurityGroupIds
    • 監視対象とするセキュリティグループのID、複数指定したい場合はカンマで区切って指定可能
    • sg-1234567890abcdef0,sg-0987654321abcdef0

3分ほどでデプロイが完了します。
SNSで設定したメールアドレス宛にサブスクリプションの承認依頼メールが届くため、Confirm subscriptionで承認します。

セキュリティグループを変更

指定したセキュリティグループのインバウンドルールにSSHポートのルールを追加します。
変更して数秒後、メール通知が届きました!

セキュリティグループのRDP_SSH変更通知_-_matsunami_kana_classmethod_jp_-_Classmethod_jp_メール

今回指定した特定のポート(RDP/SSH)以外は、メール通知がとばないことも確認できました。

最後に

今回は特定のセキュリティグループ・ポートが変更されたことを検知して、メール通知させる方法をご紹介しました。

EventBridgeRuleのEventPatternを変更することで、様々な条件に合わせたイベントを検知可能になります。
ぜひカスタマイズしてお使いください。

最後までお読みいただきありがとうございました! どなたかのお役に立てれば幸いです。

以上、おつまみ(@AWS11077)でした!

参考

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.